package com.sakura.probe.service.impl;
import cn.hutool.json.JSONUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.sakura.probe.common.api.CommonResult;
import com.sakura.probe.common.api.FileStateEnum;
import com.sakura.probe.dto.ImageHolder;
import com.sakura.probe.mapper.PersonInfoMapper;
import com.sakura.probe.mapper.TopicImgMapper;
import com.sakura.probe.mapper.VideoMapper;
import com.sakura.probe.nosql.redis.RedisKey;
import com.sakura.probe.nosql.redis.RedisService;
import com.sakura.probe.pojo.PersonInfo;
import com.sakura.probe.pojo.Topic;
import com.sakura.probe.pojo.TopicImg;
import com.sakura.probe.pojo.Video;
import com.sakura.probe.service.OssService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * oss上传管理Service实现类
 */
@Service
public class OssServiceImpl implements OssService {

    @Value("${aliyun.oss.bucketName}")
    private String ALIYUN_OSS_BUCKET_NAME;
    @Value("${aliyun.oss.endpoint}")
    private String ALIYUN_OSS_ENDPOINT;
    @Value("${aliyun.oss.dir-headImg-prefix}")
    private String HEADIMG_PREFIX;
    @Value("${aliyun.oss.dir-topic-prefix}")
    private String TOPIC_PREFIX;
    @Value("${aliyun.oss.dir-video-prefix}")
    private String VIDEO_PREFIX;

    //图片URL过期时间为10年  3600l* 1000*24*365*10
    private final long EXPIRATION = 36001 * 1000 * 24 * 365 * 10;

    private final String WATERMARK_PRE = "?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,size_20,text_";

    private final String WATERMARK_SUFFIX = ",color_FFFFFF,shadow_50,t_100,g_se,x_10,y_10";


    @Autowired
    private OSSClient ossClient;

    @Autowired
    private PersonInfoMapper personMapper;

    @Autowired
    private TopicImgMapper topicImgMapper;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private RedisService redisService;



    /**
     * 上传一张图片到阿里云OSS中
     * @param file 需要上传的图片输入流
     * @return
     */
    @Override
    @Transactional
    public CommonResult addHeadImage(PersonInfo person, String oldUrl, MultipartFile file) {
        //上传图片到阿里云中并返回成功上传后的图片名
        ImageHolder holder = addFileToOss(file,HEADIMG_PREFIX);
        if (holder.getStateEnum().getState()>0){
            //获取上传图片后的URL
            String imgUrl = getNewFileUrl(holder.getFileName(),HEADIMG_PREFIX);
            person.setHeadImg(imgUrl);
            //通过用户id修改图片的url
            int effectedNum = personMapper.updateById(person);
            if (effectedNum>0){
                try {
                    //插入成功则删除原来的图片地址(这里要判断该图片点赞)
                    if (!oldUrl.contains("default.jpeg")){
                        ossClient.deleteObject(ALIYUN_OSS_BUCKET_NAME,oldUrl.substring(oldUrl.lastIndexOf("probe")));
                        redisService.set(RedisKey.getPersonInfo()+person.getUserId(), JSONUtil.toJsonStr(person));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return CommonResult.failed(FileStateEnum.DELETE_FILE_FAIL.getStateInfo());
                }
                return CommonResult.success(FileStateEnum.UPLOAD_FILE_SUCCESS.getStateInfo());
            }else {
                return CommonResult.failed(FileStateEnum.UPLOAD_FILE_FAIL.getStateInfo());
            }
        }else {
            return CommonResult.failed(FileStateEnum.UPLOAD_FILE_FAIL.getStateInfo());
        }
    }

    /**
     * 批量上传图片到阿里云OSS中
     * @param topicId
     * @param fileList
     * @return
     */
    @Override
    public CommonResult batchAddImage(Long topicId,String waterMark ,List<MultipartFile> fileList) {
        ImageHolder temp;
        TopicImg topicImg = null;
        for (MultipartFile multipartFile:fileList){
            temp = addFileToOss(multipartFile,TOPIC_PREFIX);
            if (temp.getStateEnum().getState()<0){
                return CommonResult.failed(FileStateEnum.UPLOAD_FILE_FAIL.getStateInfo());
            }
            //获取新生成的新的图片url
            String url = getNewFileUrl(temp.getFileName(),TOPIC_PREFIX);
            //为图片添加水印(水印名要用Base64编码)
            url += WATERMARK_PRE + getBase64("@"+waterMark) + WATERMARK_SUFFIX;
            //添加进数据库中
            topicImg = new TopicImg(topicId,url);
            topicImgMapper.insert(topicImg);
        }
        return CommonResult.success("添加成功");
    }

    /**
     * 视频上传
     * @param topic
     * @param fileList
     * @return
     */
    @Override
    public CommonResult addVideo(Topic topic, List<MultipartFile> fileList) {
        ImageHolder holder = addFileToOss(fileList.get(0), VIDEO_PREFIX);
        if (holder.getStateEnum().getState()>0){
            Video condition = new Video(topic.getTopicId(),
                    getNewFileUrl(holder.getFileName(),VIDEO_PREFIX));
            int effectNum = videoMapper.insert(condition);
            return effectNum>0?CommonResult.success(FileStateEnum.INSERT_SUCCESS.getStateInfo()):
                    CommonResult.failed(FileStateEnum.INSERT_FAIL.getStateInfo());
        }else {
            return CommonResult.failed(FileStateEnum.UPLOAD_FILE_FAIL.getStateInfo());
        }
    }

    @Override
    public void deleteImage(String url) {
        ossClient.deleteObject(ALIYUN_OSS_BUCKET_NAME,url);
    }


    /**
     * 获取成功上传后文件的url
     * @param fileName 文件名
     * @param dirPre 上传文件的所在路径
     * @return
     */
    private String getNewFileUrl(String fileName,String dirPre) {
        String imgUrl = "";
        if (!StringUtils.isEmpty(fileName)){
            String[] split = fileName.split("/");
            String key = dirPre + split[split.length-1];
            Date expiration =  new Date(System.currentTimeMillis() + EXPIRATION);
            //生成URL
            URL url = ossClient.generatePresignedUrl(ALIYUN_OSS_BUCKET_NAME,key,expiration);
            if (null != url){
                imgUrl = url.toString();
            }
        }
        return "".equals(imgUrl)?imgUrl:imgUrl.substring(0,imgUrl.indexOf("?"));
    }

    /**
     * 上传至OSS中并返回新生成的文件名
     * @param file 需要上传的文件图片
     * @return
     */
    private ImageHolder addFileToOss(MultipartFile file,String filePath) {
        String fileName = null;
        InputStream instream = null;
        try {
            //根据原始文件名随机生成新的文件名
            fileName = getRandomName(file.getOriginalFilename());
            instream = file.getInputStream();
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = ossClient.putObject(ALIYUN_OSS_BUCKET_NAME, filePath + fileName, instream, objectMetadata);
        } catch (IOException e) {
            return new ImageHolder(FileStateEnum.UPLOAD_FILE_FAIL);
        } finally {
            try {
                if (null != instream){
                    instream.close();
                }
            }catch (IOException e){
                return new ImageHolder(FileStateEnum.UPLOAD_FILE_FAIL);
            }
        }
        return new ImageHolder(FileStateEnum.UPLOAD_FILE_SUCCESS,fileName);
    }

    /**
     * 随机生成文件名
     * @param originalFileName 原始的文件名
     * @return
     */
    private String getRandomName(String originalFileName) {
        //获取文件的后缀名
        String subString = originalFileName.substring(originalFileName.lastIndexOf("."))
                .toLowerCase();
        Random random = new Random();
        return random.nextInt(10000) + System.currentTimeMillis() + subString;
    }

    /**
     * 判断OSS服务文件上传时文件的类型contentType
     * @param fileNameExtension
     * @return
     */
    private String getContentType(String fileNameExtension){
        if (fileNameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (fileNameExtension.equalsIgnoreCase(".mp4")) {
            return "video/mp4";
        }
        if (fileNameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (fileNameExtension.equalsIgnoreCase(".jpeg") ||
                fileNameExtension.equalsIgnoreCase(".jpg") ||
                fileNameExtension.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (fileNameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (fileNameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (fileNameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (fileNameExtension.equalsIgnoreCase(".pptx") ||
                fileNameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (fileNameExtension.equalsIgnoreCase(".docx") ||
                fileNameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (fileNameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }

    /**
     * 对字符串进行Base64编码
     * @param str
     * @return
     */
    private String getBase64(String str) {
        if (str == null) return null;
        return (new sun.misc.BASE64Encoder()).encode( str.getBytes() );
    }
}
